.386
.model flat, stdcall
option casemap:none
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<外部依赖<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc 
includelib kernel32.lib 
include gdi32.inc
includelib gdi32.lib
includelib msvcrt.lib
include comdlg32.inc
includelib comdlg32.lib 

;图像信息
ImageInfoStruct STRUCT
    pathPointer LPCTSTR ?
    h DWORD ?
    w DWORD ?
ImageInfoStruct ENDS 


;游戏对象
GameObject STRUCT
    id DWORD ?      ;
    kind DWORD ?    ;类型，不同类型编号对应不同的处理
    posx SDWORD ?
    posy SDWORD ?
    himg HBITMAP ?   ;对应的贴图句柄
    imgh DWORD ?   ;对应贴图的高度
    imgw DWORD ?    ;对应贴图的宽度
    active DWORD ?
    collsionWidth DWORD  ?  ;碰撞体宽度
    collsionHeight DWORD ?  ;碰撞体高度
GameObject ENDS

 RGB macro red,green,blue
        xor eax,eax
        mov ah,blue
        shl eax,8
        mov ah,green
        mov al,red
 endm


printf PROTO C: ptr byte, :vararg
;装载资源，这里主要是将位图资源加载并设置到相应的句柄中
SetResource PROTO stdcall
;装载位图，不需要管，已经设置好，只需要按照需要传递参数即可
LoadBitMap PROTO stdcall imageInfo:ImageInfoStruct, imageHandleAdd:PTR HBITMAP 

;绘制游戏对象
GameObjectPaint PROTO hWnd:HWND, id:DWORD
;根据ID获取GameObJectIndex
GetGameObjectIndexByID PROTO id:DWORD
;根据下标获取
GetGameObjectByIndex PROTO index:DWORD
;背景绘制
BackGroundPaint PROTO hWnd:HWND, id:DWORD
;双缓冲贴图
FinalPaint PROTO hWnd:HWND
;GameObject移动
TranslateGameObject PROTO id:DWORD, x:SDWORD, y:SDWORD
;将系统时间转换为毫秒
TransformTimeStruct PROTO timeStruct:SYSTEMTIME
;获取系统时间，结果在curTime内
GetTime PROTO
;获取变化时间
GetDeltaTime PROTO 
;通过速度计算位移量
CalDisplacementByVelocity PROTO velocity:SWORD, deltaTime:WORD
;改变游戏图像
ChangeGameObjectImg PROTO id:DWORD, hImg:HBITMAP, imgWidth:DWORD, imgHeight:DWORD
;增加游戏对象，通过eax返回编号
AddGameObject PROTO gb:GameObject
;删除游戏对象，通过eax 0删除失败，1删除成功
DeleteGameObject PROTO id:DWORD
;刷新列表
RefreshObjectList PROTO
;内存删除
MemoryDeleteGameObject PROTO  id:DWORD
;刷新
RefreshObjectList PROTO
;获取游戏对象，通过eax获取偏移地址
GetGameObject PROTO id:DWORD 
;移动对象
MoveGameObject PROTO  sId:DWORD, dId:DWORD
GetGameObjectSize PROTO

;UI部分
UI_TextDraw PROTO hFont:HFONT, posx:SDWORD, posy:SDWORD, content: PTR BYTE, len:DWORD, color:COLORREF
CreateStandFont PROTO  fWidth:SDWORD, fHeight:SDWORD, fBlack:DWORD, fontName: PTR DWORD

;框架启用
FrameEnd PROTO
FrameInit PROTO hWnd:HWND, windowWidth:DWORD, windowHeight:DWORD



;碰撞检测
CollisionDetectAllGameObjects PROTO
DealWithCollsionEvent PROTO obj1:DWORD, obj2:DWORD
Collsion_Detect PROTO obj1_id:dword, obj2_id:dword
Cal_core_pos  PROTO obj:PTR GameObject,obj_x:PTR dword,obj_y:PTR dword


.data
objectArraySize DWORD 0
objectLists GameObject  100 dup(<0,0,0,0,0,0,0,0,0,0>)
mdc  HDC ?
hMaskDC HDC ?
;为双缓冲设计
lmdc HDC ?
lbmp HBITMAP ?
wWidth DWORD ?
wHeight DWORD ?

GameObjectSize equ SIZEOF GameObject
PreTime DWORD 0
CurTime DWORD 0
DeltaTime WORD 0

hDefaultFont HFONT ?

staticIDCount DWORD 0
.code
;----------------------------------My Function -----------------------------

;----------------------------------框架函数---------------------------------




;获取GameObject
GetGameObject PROC uses ebx id:DWORD
    LOCAL sizeOFgb :DWORD
    mov eax, GameObjectSize
    mov sizeOFgb, eax
    lea ebx, objectLists

    mov ecx, 0
    .WHILE  ecx < objectArraySize
        mov eax,  [ebx]
        .Break .IF (eax == id)
        add ebx, sizeOFgb
        inc ecx
    .ENDW
    .IF ecx < objectArraySize
        mov eax, ebx
        mov edx, NULL
        .IF [ebx+28] == edx
               mov eax, NULL
        .ENDIF
        ret
    .ELSE

        mov eax, NULL
        ret
    .ENDIF
GetGameObject endp

;通过下标获取
GetGameObjectByIndex PROC index:DWORD
    mov ebx, offset objectLists
    mov eax, index
    mov ecx, GameObjectSize
    mul ecx
    add eax, ebx
    ret
GetGameObjectByIndex endp

;根据ID获取GameObJectIndex
GetGameObjectIndexByID PROC id:DWORD
    LOCAL sizeOFgb :DWORD
    mov eax, GameObjectSize
    mov sizeOFgb, eax
    lea ebx, objectLists

    mov ecx, 0
    .WHILE  ecx < objectArraySize
        mov eax,  [ebx]
        .Break .IF (eax == id)
        add ebx, sizeOFgb
        inc ecx
    .ENDW
    .IF ecx < objectArraySize
        mov eax, ecx
        ret
    .ELSE
        mov eax, -1
        ret
    .ENDIF

GetGameObjectIndexByID endp

;位图装载 无返回值
LoadBitMap PROC stdcall imageInfo:ImageInfoStruct, imageHandle:PTR HBITMAP
    mov ebx, imageInfo.pathPointer
    invoke LoadImage, NULL, imageInfo.pathPointer ,IMAGE_BITMAP, imageInfo.w, imageInfo.h, LR_LOADFROMFILE
    mov ebx, imageHandle
    mov [ebx], eax
    ret
LoadBitMap endp



BackGroundPaint PROC hWnd, id:DWORD
    ;LOCAL tmpDC : HDC
    ;invoke GetDC, hWnd
    ;mov tmpDC, eax
    invoke GetGameObject, id
    mov ebx, eax
    .IF ebx == NULL
        ret
    .ENDIF

    mov eax, [ebx + 16]
    .IF eax == 0
        ;invoke ReleaseDC, hWnd, tmpDC
        ret
    .ELSE
        invoke SelectObject, mdc, [ebx+16]
        invoke BitBlt, lmdc, 0, 0, [ebx+24], [ebx+20], mdc, 0, 0, SRCCOPY
    .ENDIF
        ;invoke ReleaseDC, hWnd, tmpDC
    ret
BackGroundPaint endp

;绘制游戏对象
GameObjectPaint  PROC uses ebx hWnd:HWND, id:DWORD
    ;LOCAL tmpDC : HDC
    LOCAL  hMaskBMP : HBITMAP

    invoke GetGameObject, id
    mov ebx, eax
    .IF eax == NULL
        ret
    .ENDIF
    mov eax, [ebx + 16]
    .IF eax == NULL
        ret
    .ELSE
        invoke SelectObject, mdc, [ebx+16]
        invoke CreateBitmap, [ebx + 24], [ebx + 20], 1, 1, NULL
        mov hMaskBMP, eax
        invoke SelectObject, hMaskDC, hMaskBMP

        RGB 0,0,0
        invoke SetBkColor, mdc, eax
        invoke BitBlt, hMaskDC, 0, 0, [ebx + 24], [ebx + 20], mdc, 0, 0, SRCCOPY
        
        ;双缓冲方式
        invoke BitBlt, lmdc, [ebx+8], [ebx+12], [ebx+24], [ebx+20], mdc, 0, 0, SRCINVERT
        invoke BitBlt, lmdc, [ebx+8], [ebx+12], [ebx+24], [ebx+20], hMaskDC, 0, 0, SRCAND
        invoke BitBlt, lmdc, [ebx+8], [ebx+12], [ebx+24], [ebx+20], mdc, 0, 0, SRCINVERT
    .ENDIF
        ;invoke ReleaseDC, hWnd, tmpDC
        invoke DeleteObject, hMaskBMP
    ret
GameObjectPaint endp

FinalPaint PROC hWnd:HWND
    LOCAL tmpDC:HDC
    invoke GetDC, hWnd
    mov tmpDC, eax
    invoke BitBlt, tmpDC, 0, 0, wWidth, wHeight, lmdc, 0, 0, SRCCOPY
    invoke ReleaseDC, hWnd, tmpDC
    ret
FinalPaint endp


;GameObject移动
TranslateGameObject PROC uses ebx id:DWORD, x:SDWORD, y:SDWORD
    LOCAL gb :DWORD
    invoke GetGameObject, id

    .IF eax == NULL
        ret
    .ENDIF
    add eax, 8
    mov ebx, eax
    mov eax, [ebx]
    add eax, x
    mov [ebx], eax

    add ebx, 4
    mov eax, [ebx]
    add eax, y
    mov [ebx], eax
    ret
TranslateGameObject endp

;通过SetTimer来进行全局时间控制
GetTime PROC 
    LOCAL timeStruct:SYSTEMTIME
    LOCAL tmpTime:DWORD
    lea eax, timeStruct
    mov tmpTime, eax
    invoke GetLocalTime, tmpTime
    invoke TransformTimeStruct, timeStruct
    ;返回值为eax
    ret
GetTime endp

;将时间结构体的时，分，秒，毫秒转换为毫秒整数
TransformTimeStruct PROC uses ebx edx timeStruct:SYSTEMTIME
    LOCAL tmpCount:DWORD
    LOCAL totalCount:DWORD
    mov totalCount, 0
    mov ax, timeStruct.wHour
    mov ebx, 3600000
    mul ebx
    push edx
    push eax
    pop tmpCount
    mov eax, totalCount
    add eax, tmpCount
    mov totalCount, eax

    xor eax, eax
    xor edx, edx
    mov ax, timeStruct.wMinute
    mov bx, 60000
    mul bx
    push dx
    push ax
    pop tmpCount
    mov eax, totalCount
    add eax, tmpCount
    mov totalCount, eax

    xor eax, eax
    xor edx, edx
    mov ax, timeStruct.wSecond
    mov bx, 1000
    mul bx
    push dx
    push ax
    pop tmpCount
    mov eax, totalCount
    add eax, tmpCount
    
    xor edx, edx
    mov dx, timeStruct.wMilliseconds
    add eax, edx
    ret
TransformTimeStruct endp

;获取preTime和curTime的差
GetDeltaTime proc
    mov eax, CurTime
    mov PreTime, eax
    invoke GetTime
    mov CurTime, eax
    sub eax, PreTime
    ;返回值为ax
    ret
GetDeltaTime endp

;通过速度计算位移量
CalDisplacementByVelocity PROC uses edx ebx  velocity:SWORD, deltaTime:WORD
    LOCAL distence:SDWORD
    xor eax, eax
    xor edx, edx
    mov ax, velocity
    imul deltaTime
    mov bx, 100
    idiv bx
    movsx eax, ax
    ret
CalDisplacementByVelocity endp


;添加GameObject
AddGameObject PROC gb:GameObject
    LOCAL retId:DWORD
    mov retId, 0
    lea ebx, objectLists
    mov eax, DWORD PTR [ebx + 28]
    .WHILE eax != 0
        inc retId
        add ebx, GameObjectSize
        mov eax, DWORD PTR [ebx + 28]
    .ENDW
    
    push staticIDCount
    pop [ebx]
    push gb.posx
    pop [ebx+8]
    push gb.posy
    pop [ebx+12]
    push gb.kind
    pop [ebx+4]
    push gb.imgh
    pop [ebx+20]
    push gb.imgw
    pop [ebx+24]
    push gb.himg
    pop [ebx+16]
    mov eax, 1
    mov DWORD PTR [ebx+28], eax  ;标识正在使用
    push gb.collsionWidth
    pop [ebx + 32]
    push gb.collsionHeight
    pop [ebx + 36]

    inc objectArraySize
    mov eax, staticIDCount
    inc staticIDCount
    ret
AddGameObject endp


GetGameObjectSize PROC
    mov eax, objectArraySize
    ret
GetGameObjectSize endp

;删除游戏对象
DeleteGameObject PROC uses ebx, id:DWORD
    LOCAL count : DWORD

    invoke GetGameObject, id
    mov ebx, eax
    mov eax, 0
    mov [ebx+28], eax
    ret
DeleteGameObject endp

;内存删除
MemoryDeleteGameObject PROC  id:DWORD
    LOCAL count : DWORD
    invoke GetGameObjectIndexByID, id
    mov ecx, eax
    mov count, eax
    .WHILE ecx < objectArraySize
        mov eax, ecx
        mov edx, eax
        inc edx
        invoke MoveGameObject, edx, eax
        inc count
        mov ecx, count
    .ENDW
    ret
MemoryDeleteGameObject endp

;刷新GameObject列表
RefreshObjectList PROC
    LOCAL count : DWORD
    mov ecx, 0
    mov ebx, offset objectLists

    mov count, ecx
    .WHILE ecx < objectArraySize
        mov eax, [ebx + 28]
        .IF eax == 0
            invoke MemoryDeleteGameObject, [ebx]
            sub ebx, GameObjectSize
            dec objectArraySize
            dec count
        .ENDIF
        add ebx, GameObjectSize
        inc count
        mov ecx, count
    .ENDW
    ret
RefreshObjectList endp

;移动游戏对象
MoveGameObject PROC uses ebx ecx, sIndex:DWORD, dIndex:DWORD
    LOCAL srcStart:DWORD
    LOCAL desStart:DWORD

    invoke GetGameObjectByIndex, sIndex
    mov srcStart, eax
    invoke GetGameObjectByIndex, dIndex
    mov desStart, eax

    .IF srcStart == NULL || desStart == NULL
        ret
    .ENDIF

    xor ebx, ebx
    mov ecx, 0
    .WHILE ecx < 10         ;10个DWORD
        mov edx, srcStart
        mov eax, desStart
        add edx, ebx
        add eax, ebx
        push [edx]
        pop [eax]
        add ebx, 4
        inc ecx
    .ENDW

        mov ebx, srcStart
        add ebx, 28
        mov eax, 0
        mov DWORD PTR [ebx], eax
    ret
MoveGameObject endp

FrameInit PROC hWnd:HWND, windowWidth:DWORD, windowHeight:DWORD
    LOCAL tmpDC : HDC
    LOCAL tmpCount : DWORD
    
    invoke FrameEnd

    invoke GetDC, hWnd
    mov tmpDC, eax
    invoke CreateCompatibleDC, tmpDC
    mov mdc, eax
    invoke CreateCompatibleDC, mdc
    mov hMaskDC, eax

    invoke CreateCompatibleDC, tmpDC
    mov lmdc, eax
    invoke CreateCompatibleBitmap, tmpDC, windowWidth, windowHeight
    mov lbmp, eax
    invoke SelectObject, lmdc, lbmp

    push windowHeight
    pop wHeight
    push windowWidth
    pop wWidth

     invoke ReleaseDC, hWnd, tmpDC

     invoke CreateStandFont, -18, -9, 300, NULL
     mov hDefaultFont, eax


     mov ebx, offset objectLists
     mov tmpCount, 0
     mov ecx, tmpCount
     .WHILE ecx < objectArraySize
            invoke DeleteGameObject, DWORD PTR [ebx]
            add ebx, GameObjectSize
            inc tmpCount
            mov ecx, tmpCount
     .ENDW
     invoke RefreshObjectList

     mov staticIDCount, 0
    ret
FrameInit endp

FrameEnd PROC
    .IF mdc != NULL
        invoke DeleteDC, mdc
    .ENDIF
    .IF hMaskDC != NULL
        invoke DeleteDC, hMaskDC
    .ENDIF
    .IF lmdc != NULL
        invoke DeleteDC, lmdc
    .ENDIF
    .IF lbmp != NULL
        invoke DeleteObject, lbmp
    .ENDIF
    ret
FrameEnd endp

Cal_core_pos  PROC obj:PTR GameObject,obj_x:PTR dword,obj_y:PTR dword
    mov ebx,obj
    mov eax,[ebx+32]
    shr eax,1
    add eax,[ebx+8]
    mov ecx,obj_x
    mov [ecx],eax

    mov eax,[ebx+36]
    shr eax,1
    add eax,[ebx+12]
    mov ecx,obj_y
    mov [ecx],eax
    ret
Cal_core_pos  endp

Collsion_Detect  PROC obj1_id:dword,obj2_id:dword
    LOCAL obj1:dword
    LOCAL obj2:dword
    LOCAL obj1_core_x:dword
    LOCAL obj1_core_y:dword
    LOCAL obj2_core_x:dword
    LOCAL obj2_core_y:dword
    LOCAL x_dis:SDWORD
    LOCAL y_dis:SDWORD

    invoke GetGameObject,obj1_id
    mov obj1,eax
    invoke GetGameObject,obj2_id
    mov obj2,eax

    .IF obj1 == NULL || obj2 == NULL
        mov eax, 0    
        ret
    .ENDIF

    invoke Cal_core_pos,obj1, addr obj1_core_x, addr obj1_core_y
    invoke Cal_core_pos,obj2, addr obj2_core_x, addr obj2_core_y

    mov ebx,obj1_core_x
    sub ebx,obj2_core_x
    mov x_dis,ebx
    .IF x_dis < 0
        neg x_dis
    .ENDIF

    mov ebx,obj1_core_y
    sub ebx,obj2_core_y
    mov y_dis,ebx
    .IF y_dis < 0 
        neg y_dis
    .ENDIF

    mov ebx,obj1
    mov ecx,obj2
    mov eax,[ebx+32]
    add eax,[ecx+32]
    shr eax,1
    ;mov esi,11
    ;idiv esi
    sub x_dis,eax

    mov eax,[ebx+36]
    add eax,[ecx+36]
    shr eax,1
    ;xor edx,edx
    ;idiv esi
    sub y_dis,eax

    .IF x_dis < 0 && y_dis < 0
        mov eax, 1
        ret
    .ENDIF
    xor eax, eax
    ret
Collsion_Detect  endp

CollisionDetectAllGameObjects PROC
    LOCAL mainCount : DWORD
    LOCAL subCount : DWORD
    LOCAL isCollsion : DWORD
    LOCAL obj1ID : DWORD
    LOCAL obj2ID : DWORD

    mov mainCount, 1
    mov ecx, mainCount
    .WHILE ecx < objectArraySize
        mov eax, mainCount
        inc eax
        mov subCount, eax
        mov ecx, subCount
        invoke GetGameObjectByIndex, mainCount
        push [eax]
        pop obj1ID
        mov ecx, subCount
        .WHILE ecx < objectArraySize
            invoke GetGameObjectByIndex, subCount
            push [eax]
            pop obj2ID
            invoke Collsion_Detect, obj1ID, obj2ID
            .IF eax == 1
                invoke DealWithCollsionEvent, obj1ID, obj2ID
            .ENDIF
            inc subCount
            mov ecx, subCount
        .ENDW
        inc mainCount
        mov ecx, mainCount
    .ENDW
    ret
CollisionDetectAllGameObjects endp

;UI绘制部分
UI_TextDraw PROC hFont:HFONT, posx:SDWORD, posy:SDWORD,  content:PTR BYTE, len:DWORD, color:COLORREF
    
    .IF hFont == NULL
        push hDefaultFont
        POP hFont
    .ENDIF
    invoke SelectObject, lmdc, hFont
    invoke SetTextColor, lmdc, color
    invoke SetBkMode, lmdc, TRANSPARENT
    invoke TextOut, lmdc, posx, posy, content,  len
    RGB 0,0,0
    invoke SetTextColor, lmdc, eax
    ret
UI_TextDraw endp

CreateStandFont PROC  fWidth:SDWORD, fHeight:SDWORD, fBlack:DWORD, fontName: PTR DWORD
    invoke CreateFont,\
        fWidth,fHeight,\
        0, 0, fBlack,\
        0, 0, 0,\
        DEFAULT_CHARSET,\
        OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS,\
        DEFAULT_QUALITY,\
        FF_DONTCARE,\
        fontName
    ret 
CreateStandFont endp

ChangeGameObjectImg PROC id:DWORD, hImg:HBITMAP, imgWidth:DWORD, imgHeight:DWORD
    invoke GetGameObject, id
    mov ebx, eax
    .IF ebx == NULL
        ret
    .ENDIF
    push hImg
    pop [ebx+16]
    push imgWidth
    pop [ebx+24]
    push imgHeight
    pop [ebx+20]
    ret
ChangeGameObjectImg endp
end